package com.bacon.gmall.gateway.filter;

import com.alibaba.fastjson.JSONObject;
import com.bacon.gmall.common.result.Result;
import com.bacon.gmall.common.result.ResultCodeEnum;
import com.bacon.gmall.gateway.constant.RedisConst;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

/**
 * @author： bacon、
 * @version： 1.0
 * @create： 2021-01-03 21:28
 * @description: 自定义全局过滤器
 * 判断用户是否需要登录
 * 1、需要登录
 * 2、可登录或不登录
 * 3、需要登录
 * 4、内部资源
 */
@Component
public class LoginGlobalFilter implements GlobalFilter, Ordered {

    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    public static final String TOKEN = "token";
    public static final String USERTEMPID = "userTempId";


    @Autowired
    private RedisTemplate redisTemplate;

    @Value("${auth.url}")
    private String[] authUrls;


    //过滤器方式
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //exchange == 请求对象  响应对象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        //查看请求信息
        /*System.out.println("request.getPath() -----> " + request.getPath());
        System.out.println("request.getURI().getRawSchemeSpecificPart() -----> " +
                request.getURI().getRawSchemeSpecificPart());

        System.out.println("request.getURI().getPath() -----> " + request.getURI().getPath());
        System.out.println("request.getRemoteAddress().getHostString() -----> " +
                request.getRemoteAddress().getHostString());
        System.out.println("request.getRemoteAddress().getHostName() -----> " +
                request.getRemoteAddress().getHostName());*/
        /**
         * 输入地址为    http://list.gmall.com/list.html?category3Id=61
         * request.getPath() -----> /list.html
         * request.getURI().getRawSchemeSpecificPart() -----> //list.gmall.com/list.html?category3Id=61
         * request.getURI().getPath() -----> /list.html
         * request.getRemoteAddress().getHostString() -----> payment.gmall.com
         * request.getRemoteAddress().getHostName() -----> payment.gmall.com
         */

        /**
         * 那些微服务走网关 ： 用户微服务，商品微服务，搜索微服务，异步，同步
         * VUE 访问网关，路由转发到某一个微服务     异步的    JSON
         * 搜索微服务 Feign远程调用 商品微服务     异步的    JSON
         * HTML 访问网关 路由 页面微服务 页面渲染   同步
         */

        /**
         * 结论
         * 异步： 未登录  返回值 result.fail   208:未登录   JSON格式返回
         * 页面接收到208弹出一个弹出框，让用户登录
         *
         * 同步： 未登录  重定向  去登录页面
         *
         * 内部资源： 不允许访问
         */

        String path = request.getURI().getPath();

        //内部资源 209 无权限
        if (antPathMatcher.match("/**/inner/**", path)) {

            //返回结果  209 没权限
            return out(response,ResultCodeEnum.PERMISSION);
        }


        /**
         * 异步 : 必须登录
         */
        String userId = getUserId(request);
        if (antPathMatcher.match("/**/auth/**", path)) {
            //未登录
            if (StringUtils.isEmpty(userId)) {
                //返回结果  208 未登录
                return out(response,ResultCodeEnum.LOGIN_AUTH);
            }
        }

        /**
         * 同步
         */
        for (String authUrl : authUrls) {
            if (path.indexOf(authUrl) != -1 && StringUtils.isEmpty(userId)){
                //未登录 重定向到登录页面
                response.setStatusCode(HttpStatus.SEE_OTHER);

                try {
                    response.getHeaders().add(HttpHeaders.LOCATION,
                            "//passport.gmall.com/login.html?originUrl="+
                                    URLEncoder.encode(request.getURI().getRawSchemeSpecificPart(),"UTF-8"));
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }

                //响应完成
                return response.setComplete();
            }
        }

        //购物车 --->判断如果用户Id存在 传递Id  购物车不登录就访问
        if (null != userId){
            /**
             * request.getHeaders().add("userId",userId);
             * 运行此行代码出错，不可修改请求头
             *
             * 所以需要创建新得请求设置UserId发送给wel-all微服务
             */
            request.mutate().header("userId",userId);
        }
        String userTempId = getUserTempId(request);
        if (null != userTempId){
            request.mutate().header("userTempId",userTempId);
        }

        return chain.filter(exchange);
    }

    public String getUserTempId(ServerHttpRequest request){
        String userTempId = request.getHeaders().getFirst(USERTEMPID);
        if (StringUtils.isEmpty(userTempId)) {
            HttpCookie cookie = request.getCookies().getFirst(USERTEMPID);
            if (null != cookie) {
                userTempId = cookie.getValue();
            }
        }
        return userTempId;
    }

    //统一异步请求返回值
    public Mono<Void> out(ServerHttpResponse response, ResultCodeEnum resultCodeEnum) {
        //返回结果  209
        Result result = Result.build(null, resultCodeEnum);

        //转化为JSON串
        String jsonObject = JSONObject.toJSONString(result);

        DataBufferFactory dataBufferFactory = response.bufferFactory();
        DataBuffer wrap = dataBufferFactory.wrap(jsonObject.getBytes());

        //转为格式
        response.getHeaders().add(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8");
        return response.writeWith(Mono.just(wrap));
    }


    //获取用户Id
    private String getUserId(ServerHttpRequest request) {

        /**
         * 用户ID可能存在的地方，
         * 请求头中
         * Cookie中
         */
        String token = request.getHeaders().getFirst(TOKEN);
        if (StringUtils.isEmpty(token)) {
            HttpCookie cookie = request.getCookies().getFirst(TOKEN);
            if (null != cookie) {
                token = cookie.getValue();
            }
        }

        if (token != null) {

            if (redisTemplate.hasKey(RedisConst.USER_LOGIN_KEY_PREFIX + token)) {
                return (String) redisTemplate.opsForValue().get(RedisConst.USER_LOGIN_KEY_PREFIX + token);
            }
        }
        return null;
    }

    //排序
    //默认9大全局过滤器 + 自定义过滤器 ------> 10个全局过滤器
    @Override
    public int getOrder() {
        return 0;
    }
}
